use std::collections::HashMap;
use xelis_vm::ValueCell;
use crate::{
    asset::AssetData,
    context::NoOpBuildHasher,
    contract::DeterministicRandom,
    crypto::Hash,
    versioned_type::VersionedState
};

#[derive(Debug, Clone)]
pub struct AssetChanges {
    // The asset data
    pub data: (VersionedState, AssetData),
    // The supply of the asset
    pub circulating_supply: (VersionedState, u64),
}

// Contract cache containing all the changes/cache made by the contract
#[derive(Debug, Clone)]
pub struct ContractCache {
    // The random number generator
    // It is deterministic so we can replay the contract
    // If none, it means no Random was initiated / needed yetc
    // Lazy init using the Option
    // This is shared between all executions of the same contract
    pub random: Option<DeterministicRandom>,
    // The storage of the contract
    // All the changes made by the contract are stored here
    pub storage: HashMap<ValueCell, Option<(VersionedState, Option<ValueCell>)>>,
    // The contract balances
    // Those already present are loaded due to the deposits to be added
    // If its none, it means we don't have any balance yet
    pub balances: HashMap<Hash, Option<(VersionedState, u64)>>,
    // Memory Storage
    // This is shared between all executions of the same contract
    pub memory_shared: HashMap<ValueCell, ValueCell>,
    // Temporary Memory Storage
    // This is only available for the current contract call
    pub memory: HashMap<ValueCell, ValueCell>,
    // Custom events generated by the contract
    pub events: HashMap<u64, Vec<ValueCell>, NoOpBuildHasher>,
}

impl Default for ContractCache {
    fn default() -> Self {
        Self::new()
    }
}

impl ContractCache {
    pub fn new() -> Self {
        Self {
            random: None,
            storage: HashMap::new(),
            balances: HashMap::new(),
            memory_shared: HashMap::new(),
            memory: HashMap::new(),
            events: HashMap::default()
        }
    }

    // Clean the contract cache when it is stored
    pub fn clean_up(&mut self) {
        // We clean the temporary memory from it
        self.memory.clear();
    }
}